/*
 * Copyright 2002-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

/**
 * 访问 Spring bean 容器的根接口。
 * <p>这是 bean 容器的基本客户端视图； 其他接口如{@link ListableBeanFactory}和{@link org.springframework.beans.factory.config.ConfigurableBeanFactory}可用于特定目的。
 *
 * <p>该接口由包含多个 bean 定义的对象实现，每个定义由一个字符串名称唯一标识。
 * 根据 bean 定义，工厂将返回包含对象的独立实例（原型设计模式），或单个共享实例（单例设计模式的高级替代方案，其中实例是范围内的单例）工厂）。
 * 返回哪种类型的实例取决于 bean factory 配置：API 是相同的。
 * 从 Spring 2.0 开始，根据具体的应用程序上下文（例如 Web 环境中的“请求”和“会话”范围），可以使用更多范围。
 *
 * <p>这种方法的重点是 BeanFactory 是应用程序组件的中央注册表，并且集中了应用程序组件的配置（例如，单个对象不再需要读取属性文件）。
 * 请参阅“专家一对一 J2EE 设计和开发”的第 4 章和第 11 章，以了解这种方法的好处。
 *
 * <p>请注意，通常最好依靠依赖注入（“推送”配置）通过 setter 或构造函数来配置应用程序对象，而不是使用任何形式的“拉”配置，例如 BeanFactory 查找。
 * Spring 的依赖注入功能是使用这个 BeanFactory 接口及其子接口实现的。
 *
 * <p>通常 BeanFactory 将加载存储在配置源（例如 XML 文档）中的 bean 定义，并使用org.springframework.beans包来配置 bean。
 * 但是，实现可以简单地直接在 Java 代码中返回它根据需要创建的 Java 对象。
 * 定义的存储方式没有限制：LDAP、RDBMS、XML、属性文件等。鼓励实现支持 bean 之间的引用（依赖注入）。
 *
 * <p>与{@link ListableBeanFactory}的方法相反，此接口中的所有操作还将检查父工厂是否为{@link HierarchicalBeanFactory} 。
 * 如果在此工厂实例中未找到 bean，则会询问直接父工厂。 此工厂实例中的 Bean 应该覆盖任何父工厂中的同名 Bean。

 * <p> Bean 工厂实现应尽可能支持标准的 bean 生命周期接口。 全套初始化方法及其标准顺序是：
 * <ol>
 * <li>BeanNameAware's {@code setBeanName}
 * <li>BeanClassLoaderAware's {@code setBeanClassLoader}
 * <li>BeanFactoryAware's {@code setBeanFactory}
 * <li>EnvironmentAware's {@code setEnvironment}
 * <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
 * <li>ResourceLoaderAware's {@code setResourceLoader}（仅在应用程序上下文中运行时适用）
 * <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher} （仅适用于在应用程序上下文中运行时）
 * <li>MessageSourceAware's {@code setMessageSource}（仅在应用程序上下文中运行时适用）
 * <li>ApplicationContextAware's {@code setApplicationContext}（仅在应用程序上下文中运行时适用）
 * <li>ServletContextAware's {@code setServletContext}（仅在 web 应用上下文中运行时适用）
 * <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
 * <li>InitializingBean's {@code afterPropertiesSet}
 * <li>a custom {@code init-method} definition
 * <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
 * </ol>
 *
 * <p>在关闭 bean 工厂时，以下生命周期方法适用：
 * <ol>
 * <li>DestructionAwareBeanPostProcessors 的 {@code postProcessBeforeDestruction} 方法
 * <li>DisposableBean's {@code destroy}
 * <li>自定义 {@code destroy-method}
 * </ol>
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 13 April 2001
 * @see BeanNameAware#setBeanName
 * @see BeanClassLoaderAware#setBeanClassLoader
 * @see BeanFactoryAware#setBeanFactory
 * @see org.springframework.context.EnvironmentAware#setEnvironment
 * @see org.springframework.context.EmbeddedValueResolverAware#setEmbeddedValueResolver
 * @see org.springframework.context.ResourceLoaderAware#setResourceLoader
 * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
 * @see org.springframework.context.MessageSourceAware#setMessageSource
 * @see org.springframework.context.ApplicationContextAware#setApplicationContext
 * @see org.springframework.web.context.ServletContextAware#setServletContext
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization
 * @see InitializingBean#afterPropertiesSet
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
 * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
 * @see DisposableBean#destroy
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
 */
public interface BeanFactory {

	/**
	 *用于取消引用{@link FactoryBean}实例并将其与 FactoryBean创建的 bean 区分开来。
	 * 例如，如果名为myJndiObject的 bean 是 FactoryBean，则获取&myJndiObject将返回工厂，而不是工厂返回的实例。
	 */
	String FACTORY_BEAN_PREFIX = "&";


	/**
	 * 返回指定 bean 的一个实例，该实例可以是共享的，也可以是独立的。
	 * <p>此方法允许使用 Spring BeanFactory 作为单例或原型设计模式的替代品。 在单例 bean 的情况下，调用者可以保留对返回对象的引用。
	 * <p>将别名转换回相应的规范 bean 名称。
	 * <p>如果在这个工厂实例中找不到 bean，将询问父工厂。
	 * @param name 要检索的 bean 的名称
	 * @return bean的一个实例
	 * @throws NoSuchBeanDefinitionException 如果没有指定名称的 bean
	 * @throws BeansException 如果无法获得 bean
	 */
	Object getBean(String name) throws BeansException;

	/**
	 * 返回指定 bean 的一个实例，该实例可以是共享的，也可以是独立的。
	 * <p>行为与{@link #getBean(String)}相同，但如果 bean 不是所需类型，则通过抛出 BeanNotOfRequiredTypeException 来提供类型安全措施。
	 * 这意味着在正确投射结果时不能抛出 ClassCastException，就像{@link #getBean(String)}可能发生的那样。
	 * <p>将别名转换回相应的规范 bean 名称。
	 * <p>如果在这个工厂实例中找不到 bean，将询问父工厂。
	 * @param name 要检索的 bean 的名称
	 * @param requiredType bean 必须匹配的类型； 可以是接口或超类
	 * @return bean的一个实例
	 * @throws NoSuchBeanDefinitionException 如果没有指定名称的 bean
	 * @throws BeanNotOfRequiredTypeException 如果 bean 不是所需的类型
	 * @throws BeansException 如果无法获得 bean
	 */
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	/**
	 * 返回指定 bean 的一个实例，该实例可以是共享的，也可以是独立的。
	 * <p>允许指定显式构造函数参数/工厂方法参数，覆盖 bean 定义中指定的默认参数（如果有）。
	 * @param name 要检索的 bean 的名称
	 * @param args 使用显式参数创建 bean 实例时使用的参数（仅在创建新实例时应用，而不是检索现有实例）
	 * @return bean的一个实例
	 * @throws NoSuchBeanDefinitionException 如果没有指定名称的 bean
	 * @throws BeanDefinitionStoreException 如果已经给出参数但受影响的 bean 不是原型
	 * @throws BeansException 如果无法获得 bean
	 * @since 2.5
	 */
	Object getBean(String name, Object... args) throws BeansException;

	/**
	 * 返回与给定对象类型唯一匹配的 bean 实例（如果有）。
	 * <p>此方法进入{@link ListableBeanFactory}按类型查找领域，但也可以根据给定类型的名称转换为传统的按名称查找。
	 * 对于跨 bean 集的更广泛的检索操作，请使用{@link ListableBeanFactory}和/或{@link BeanFactoryUtils} 。
	 * @param requiredType bean 必须匹配的类型； 可以是接口或超类
	 * @return 匹配所需类型的单个 bean 的实例
	 * @throws NoSuchBeanDefinitionException 如果没有找到给定类型的 bean
	 * @throws NoUniqueBeanDefinitionException 如果找到多个给定类型的 bean
	 * @throws BeansException 如果无法获得 bean
	 * @since 3.0
	 * @see ListableBeanFactory
	 */
	<T> T getBean(Class<T> requiredType) throws BeansException;

	/**
	 * 返回指定 bean 的一个实例，该实例可以是共享的，也可以是独立的。
	 * 许指定显式构造函数参数/工厂方法参数，覆盖 bean 定义中指定的默认参数（如果有）。
	 * <p>此方法进入{@link ListableBeanFactory}按类型查找领域，但也可以根据给定类型的名称转换为传统的按名称查找。
	 * 对于跨 bean 集的更广泛的检索操作，请使用{@link ListableBeanFactory}和/或{@link BeanFactoryUtils} 。
	 * @param requiredType bean 必须匹配的类型； 可以是接口或超类
	 * @param args 使用显式参数创建 bean 实例时使用的参数（仅在创建新实例时应用，而不是检索现有实例）
	 * @return bean的一个实例
	 * @throws NoSuchBeanDefinitionException 如果没有找到给定类型的 bean
	 * @throws BeanDefinitionStoreException 如果已经给出参数但受影响的 bean 不是原型
	 * @throws BeansException 如果无法获得 bean
	 * @since 4.1
	 */
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	/**
	 * 返回指定 bean 的提供者，允许延迟按需检索实例，包括可用性和唯一性选项。
	 * @param requiredType bean 必须匹配的类型； 可以是接口或超类
	 * @return 相应 bean 的提供者
	 * @since 5.1
	 * @see #getBeanProvider(ResolvableType)
	 */
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

	/**
	 * 返回指定 bean 的提供者，允许延迟按需检索实例，包括可用性和唯一性选项。
	 * @param requiredType bean 必须匹配的类型； 可以是泛型类型声明。 请注意，与反射注入点相比，此处不支持集合类型。
	 *         要以编程方式检索与特定类型匹配的 bean 列表，请在此处指定实际 bean 类型作为参数，然后使用{@link ObjectProvider#orderedStream()}或其延迟流/迭代选项。
	 * @return 相应 bean 的提供者
	 * @since 5.1
	 * @see ObjectProvider#iterator()
	 * @see ObjectProvider#stream()
	 * @see ObjectProvider#orderedStream()
	 */
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

	/**
	 * 这个 bean 工厂是否包含具有给定名称的 bean 定义或外部注册的单例实例？
	 * <p>如果给定的名称是别名，它将被转换回相应的规范 bean 名称。
	 * <p>如果这个工厂是分层的，如果在这个工厂实例中找不到 bean，将询问任何父工厂。
	 * <p>如果找到与给定名称匹配的 bean 定义或单例实例，则无论指定的 bean 定义是具体的还是抽象的、惰性的还是急切的、范围内的，此方法都将返回true 。
	 * 		因此，请注意，此方法的true返回值并不一定表示{@link #getBean}将能够获得同名的实例。
	 * @param name 要查询的 bean 的名称
	 * @return 是否存在具有给定名称的 bean
	 */
	boolean containsBean(String name);

	/**
	 * 这个 bean 是共享单例吗？ 也就是说， {@link #getBean}总是返回相同的实例？
	 * <p>注意：此方法返回false并没有明确表示独立实例。 它表示非单例实例，也可能对应于作用域 bean。 使用{@link #isPrototype}操作显式检查独立实例。
	 * <p>将别名转换回相应的规范 bean 名称。
	 * <p>如果在这个工厂实例中找不到 bean，将询问父工厂。
	 * @param name 要查询的 bean 的名称
	 * @return 此 bean 是否对应于单例实例
	 * @throws NoSuchBeanDefinitionException 如果没有给定名称的 bean
	 * @see #getBean
	 * @see #isPrototype
	 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 这个bean是原型吗？ 也就是说， {@link #getBean}一直返回独立的实例吗？
	 * <p>注意：此方法返回false并没有明确表示单例对象。 它表示非独立实例，也可能对应于作用域 bean。 使用{@link #isSingleton}操作显式检查共享单例实例。
	 * <p>将别名转换回相应的规范 bean 名称。
	 * <p>如果在这个工厂实例中找不到 bean，将询问父工厂。
	 * @param name 要查询的 bean 的名称
	 * @return 这个 bean 是否总是交付独立的实例
	 * @throws NoSuchBeanDefinitionException 如果没有给定名称的 bean
	 * @since 2.0.3
	 * @see #getBean
	 * @see #isSingleton
	 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 检查具有给定名称的 bean 是否与指定的类型匹配。 更具体地说，检查对给定名称的{@link #getBean}调用是否会返回可分配给指定目标类型的对象。
	 * <p>将别名转换回相应的规范 bean 名称。
	 * <p>如果在这个工厂实例中找不到 bean，将询问父工厂。
	 * @param name 要查询的 bean 的名称
	 * @param typeToMatch 要匹配的类型（作为ResolvableType ）
	 * @return true 如果bean类型匹配， false ，如果它不匹配或无法尚未确定
	 * @throws NoSuchBeanDefinitionException 如果没有给定名称的 bean
	 * @since 4.2
	 * @see #getBean
	 * @see #getType
	 */
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 * 检查具有给定名称的 bean 是否与指定的类型匹配。 更具体地说，检查对给定名称的{@link #getBean}调用是否会返回可分配给指定目标类型的对象。
	 * <p>将别名转换回相应的规范 bean 名称。
	 * <p>如果在这个工厂实例中找不到 bean，将询问父工厂。
	 * @param name 要查询的 bean 的名称
	 * @param typeToMatch 要匹配的类型（作为Class ）
	 * @return true 如果bean类型匹配， false ，如果它不匹配或无法尚未确定
	 * @throws NoSuchBeanDefinitionException 如果没有给定名称的 bean
	 * @since 2.0.1
	 * @see #getBean
	 * @see #getType
	 */
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 * 确定具有给定名称的 bean 的类型。 更具体地说，确定{@link #getBean}将为给定名称返回的对象类型。
	 * <p>对于{@link FactoryBean}，返回 FactoryBean 创建的对象类型，由{@link FactoryBean#getObjectType()}公开。
	 * 		这可能会导致之前未初始化的FactoryBean初始化（请参阅{@link #getType(String, boolean)} ）。
	 * <p>将别名转换回相应的规范 bean 名称。
	 * <p>如果在这个工厂实例中找不到 bean，将询问父工厂。
	 * @param name 要查询的 bean 的名称
	 * @return bean 的类型，如果无法确定则为null
	 * @throws NoSuchBeanDefinitionException 如果没有给定名称的 bean
	 * @since 1.1.2
	 * @see #getBean
	 * @see #isTypeMatch
	 */
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 确定具有给定名称的 bean 的类型。 更具体地说，确定{@link #getBean}将为给定名称返回的对象类型。
	 * <p>对于{@link FactoryBean}，返回 FactoryBean 创建的对象类型，由{@link FactoryBean#getObjectType()}公开。
	 * 		根据allowFactoryBeanInit标志，如果没有可用的早期类型信息，这可能会导致先前未初始化的FactoryBean的初始化。
	 * <p>将别名转换回相应的规范 bean 名称。
	 * <p>如果在这个工厂实例中找不到 bean，将询问父工厂。
	 * @param name 要查询的 bean 的名称
	 * @param allowFactoryBeanInit 无论是FactoryBean可能会用于确定其对象类型的目的只是初始化
	 * @return bean 的类型，如果无法确定则为null
	 * @throws NoSuchBeanDefinitionException 如果没有给定名称的 bean
	 * @since 5.2
	 * @see #getBean
	 * @see #isTypeMatch
	 */
	@Nullable
	Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

	/**
	 * 返回给定 bean 名称的别名（如果有）。
	 * <p>在{@link #getBean}调用中使用时，所有这些别名都指向同一个 bean。
	 * <p>如果给定的名称是别名，则将返回相应的原始 bean 名称和其他别名（如果有），原始 bean 名称是数组中的第一个元素。
	 * <p>如果在这个工厂实例中找不到 bean，将询问父工厂。
	 * @param name 要查询的 bean 的名称
	 * @return 别名，如果没有，则为空数组
	 * @see #getBean
	 */
	String[] getAliases(String name);

}
